"""
云服务提供商DNS接口实现
支持阿里云、腾讯云、华为云、火山引擎
"""

from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
import logging
from django.utils import timezone

logger = logging.getLogger(__name__)


class BaseDNSProvider(ABC):
    """DNS提供商基础类"""
    
    def __init__(self, access_key: str, secret_key: str, region: str = ''):
        self.access_key = access_key
        self.secret_key = secret_key
        self.region = region
    
    @abstractmethod
    def list_domains(self) -> List[Dict[str, Any]]:
        """获取域名列表"""
        pass
    
    @abstractmethod
    def list_records(self, domain: str, zone_id: str = '') -> List[Dict[str, Any]]:
        """获取域名解析记录"""
        pass
    
    @abstractmethod
    def create_record(self, domain: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, zone_id: str = '') -> Dict[str, Any]:
        """创建解析记录"""
        pass
    
    @abstractmethod
    def update_record(self, record_id: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, domain: str = '', zone_id: str = '') -> Dict[str, Any]:
        """更新解析记录"""
        pass
    
    @abstractmethod
    def delete_record(self, record_id: str, domain: str = '', zone_id: str = '') -> bool:
        """删除解析记录"""
        pass


class AliyunDNSProvider(BaseDNSProvider):
    """阿里云DNS接口"""
    
    def __init__(self, access_key: str, secret_key: str, region: str = 'cn-hangzhou'):
        super().__init__(access_key, secret_key, region)
        try:
            from aliyunsdkcore.client import AcsClient
            from aliyunsdkalidns.request.v20150109 import DescribeDomainsRequest, DescribeDomainRecordsRequest
            from aliyunsdkalidns.request.v20150109 import AddDomainRecordRequest, UpdateDomainRecordRequest, DeleteDomainRecordRequest
            
            self.client = AcsClient(access_key, secret_key, region)
            self.DescribeDomainsRequest = DescribeDomainsRequest.DescribeDomainsRequest
            self.DescribeDomainRecordsRequest = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest
            self.AddDomainRecordRequest = AddDomainRecordRequest.AddDomainRecordRequest
            self.UpdateDomainRecordRequest = UpdateDomainRecordRequest.UpdateDomainRecordRequest
            self.DeleteDomainRecordRequest = DeleteDomainRecordRequest.DeleteDomainRecordRequest
        except ImportError:
            logger.error("阿里云SDK未安装，请安装 aliyun-python-sdk-alidns aliyun-python-sdk-core")
            raise
    
    def list_domains(self) -> List[Dict[str, Any]]:
        """获取域名列表"""
        try:
            import json
            
            request = self.DescribeDomainsRequest()
            response = self.client.do_action_with_exception(request)
            if response:
                result = json.loads(response.decode('utf-8'))
            else:
                logger.error("阿里云API返回空响应")
                return []
            
            domains = []
            for domain in result.get('Domains', {}).get('Domain', []):
                domains.append({
                    'name': domain.get('DomainName'),
                    'zone_id': domain.get('DomainId'),
                    'status': domain.get('AliDomain', True),
                })
            return domains
        except Exception as e:
            logger.error(f"获取阿里云域名列表失败: {e}")
            return []
    
    def list_records(self, domain: str, zone_id: str = '') -> List[Dict[str, Any]]:
        """获取域名解析记录"""
        try:
            import json
            
            request = self.DescribeDomainRecordsRequest()
            request.set_DomainName(domain)
            response = self.client.do_action_with_exception(request)
            if response:
                result = json.loads(response.decode('utf-8'))
            else:
                logger.error("阿里云API返回空响应")
                return []
            
            records = []
            for record in result.get('DomainRecords', {}).get('Record', []):
                records.append({
                    'record_id': record.get('RecordId'),
                    'name': record.get('RR'),
                    'type': record.get('Type'),
                    'value': record.get('Value'),
                    'ttl': record.get('TTL'),
                    'priority': record.get('Priority', 0),
                    'status': record.get('Status'),
                })
            return records
        except Exception as e:
            logger.error(f"获取阿里云解析记录失败: {e}")
            return []
    
    def create_record(self, domain: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, zone_id: str = '') -> Dict[str, Any]:
        """创建解析记录"""
        try:
            import json
            
            request = self.AddDomainRecordRequest()
            request.set_DomainName(domain)
            request.set_RR(name)
            request.set_Type(record_type)
            request.set_Value(value)
            request.set_TTL(ttl)
            if record_type == 'MX':
                request.set_Priority(priority)
            
            response = self.client.do_action_with_exception(request)
            if response:
                result = json.loads(response.decode('utf-8'))
                return {
                    'success': True,
                    'record_id': result.get('RecordId'),
                    'message': '创建成功'
                }
            else:
                return {
                    'success': False,
                    'message': 'API返回空响应'
                }
        except Exception as e:
            logger.error(f"创建阿里云解析记录失败: {e}")
            return {
                'success': False,
                'message': str(e)
            }
    
    def update_record(self, record_id: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, domain: str = '', zone_id: str = '') -> Dict[str, Any]:
        """更新解析记录"""
        try:
            import json
            
            request = self.UpdateDomainRecordRequest()
            request.set_RecordId(record_id)
            request.set_RR(name)
            request.set_Type(record_type)
            request.set_Value(value)
            request.set_TTL(ttl)
            if record_type == 'MX':
                request.set_Priority(priority)
            
            response = self.client.do_action_with_exception(request)
            if response:
                result = json.loads(response.decode('utf-8'))
                return {
                    'success': True,
                    'record_id': result.get('RecordId'),
                    'message': '更新成功'
                }
            else:
                return {
                    'success': False,
                    'message': 'API返回空响应'
                }
        except Exception as e:
            logger.error(f"更新阿里云解析记录失败: {e}")
            return {
                'success': False,
                'message': str(e)
            }
    
    def delete_record(self, record_id: str, domain: str = '', zone_id: str = '') -> bool:
        """删除解析记录"""
        try:
            request = self.DeleteDomainRecordRequest()
            request.set_RecordId(record_id)
            
            self.client.do_action_with_exception(request)
            return True
        except Exception as e:
            logger.error(f"删除阿里云解析记录失败: {e}")
            return False


class TencentDNSProvider(BaseDNSProvider):
    """腾讯云DNS接口"""
    
    def __init__(self, access_key: str, secret_key: str, region: str = 'ap-beijing'):
        super().__init__(access_key, secret_key, region)
        try:
            from tencentcloud.common import credential
            from tencentcloud.dnspod.v20210323 import dnspod_client, models
            
            cred = credential.Credential(access_key, secret_key)
            self.client = dnspod_client.DnspodClient(cred, region)
            self.models = models
        except ImportError:
            logger.error("腾讯云SDK未安装，请安装 tencentcloud-sdk-python")
            raise
    
    def list_domains(self) -> List[Dict[str, Any]]:
        """获取域名列表"""
        try:
            req = self.models.DescribeDomainListRequest()
            resp = self.client.DescribeDomainList(req)
            
            domains = []
            if resp.DomainList:
                for domain in resp.DomainList:
                    domains.append({
                        'name': domain.Name,
                        'zone_id': str(domain.DomainId),
                        'status': domain.Status,
                    })
            return domains
        except Exception as e:
            logger.error(f"获取腾讯云域名列表失败: {e}")
            return []
    
    def list_records(self, domain: str, zone_id: str = '') -> List[Dict[str, Any]]:
        """获取域名解析记录"""
        try:
            req = self.models.DescribeRecordListRequest()
            req.Domain = domain
            resp = self.client.DescribeRecordList(req)
            
            records = []
            if resp.RecordList:
                for record in resp.RecordList:
                    records.append({
                        'record_id': str(record.RecordId),
                        'name': record.Name,
                        'type': record.Type,
                        'value': record.Value,
                        'ttl': record.TTL,
                        'priority': getattr(record, 'MX', 0),
                        'status': record.Status,
                    })
            return records
        except Exception as e:
            logger.error(f"获取腾讯云解析记录失败: {e}")
            return []
    
    def create_record(self, domain: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, zone_id: str = '') -> Dict[str, Any]:
        """创建解析记录"""
        try:
            req = self.models.CreateRecordRequest()
            req.Domain = domain
            req.SubDomain = name
            req.RecordType = record_type
            req.Value = value
            req.TTL = ttl
            if record_type == 'MX':
                req.MX = priority
            
            resp = self.client.CreateRecord(req)
            return {
                'success': True,
                'record_id': str(resp.RecordId),
                'message': '创建成功'
            }
        except Exception as e:
            logger.error(f"创建腾讯云解析记录失败: {e}")
            return {
                'success': False,
                'message': str(e)
            }
    
    def update_record(self, record_id: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, domain: str = '', zone_id: str = '') -> Dict[str, Any]:
        """更新解析记录"""
        try:
            req = self.models.ModifyRecordRequest()
            req.Domain = domain
            req.RecordId = int(record_id)
            req.SubDomain = name
            req.RecordType = record_type
            req.Value = value
            req.TTL = ttl
            if record_type == 'MX':
                req.MX = priority
            
            resp = self.client.ModifyRecord(req)
            return {
                'success': True,
                'record_id': str(resp.RecordId),
                'message': '更新成功'
            }
        except Exception as e:
            logger.error(f"更新腾讯云解析记录失败: {e}")
            return {
                'success': False,
                'message': str(e)
            }
    
    def delete_record(self, record_id: str, domain: str = '', zone_id: str = '') -> bool:
        """删除解析记录"""
        try:
            req = self.models.DeleteRecordRequest()
            req.Domain = domain
            req.RecordId = int(record_id)
            
            self.client.DeleteRecord(req)
            return True
        except Exception as e:
            logger.error(f"删除腾讯云解析记录失败: {e}")
            return False


# 简化版华为云和火山引擎接口
class HuaweiDNSProvider(BaseDNSProvider):
    """华为云DNS接口（简化版）"""
    
    def list_domains(self) -> List[Dict[str, Any]]:
        logger.info("华为云接口暂未完全实现")
        return []
    
    def list_records(self, domain: str, zone_id: str = '') -> List[Dict[str, Any]]:
        logger.info("华为云接口暂未完全实现")
        return []
    
    def create_record(self, domain: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, zone_id: str = '') -> Dict[str, Any]:
        return {'success': False, 'message': '华为云接口暂未实现'}
    
    def update_record(self, record_id: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, domain: str = '', zone_id: str = '') -> Dict[str, Any]:
        return {'success': False, 'message': '华为云接口暂未实现'}
    
    def delete_record(self, record_id: str, domain: str = '', zone_id: str = '') -> bool:
        return False


class VolcengineDNSProvider(BaseDNSProvider):
    """火山引擎DNS接口（简化版）"""
    
    def list_domains(self) -> List[Dict[str, Any]]:
        logger.info("火山引擎接口暂未完全实现")
        return []
    
    def list_records(self, domain: str, zone_id: str = '') -> List[Dict[str, Any]]:
        logger.info("火山引擎接口暂未完全实现")
        return []
    
    def create_record(self, domain: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, zone_id: str = '') -> Dict[str, Any]:
        return {'success': False, 'message': '火山引擎接口暂未实现'}
    
    def update_record(self, record_id: str, name: str, record_type: str, value: str, ttl: int = 600, priority: int = 0, domain: str = '', zone_id: str = '') -> Dict[str, Any]:
        return {'success': False, 'message': '火山引擎接口暂未实现'}
    
    def delete_record(self, record_id: str, domain: str = '', zone_id: str = '') -> bool:
        return False


# 提供商工厂方法
def get_dns_provider(provider_type: str, access_key: str, secret_key: str, region: str = '') -> BaseDNSProvider:
    """根据提供商类型获取DNS提供商实例"""
    providers = {
        'aliyun': AliyunDNSProvider,
        'tencent': TencentDNSProvider,
        'huawei': HuaweiDNSProvider,
        'volcengine': VolcengineDNSProvider,
    }
    
    if provider_type not in providers:
        raise ValueError(f"不支持的DNS提供商: {provider_type}")
    
    return providers[provider_type](access_key, secret_key, region)


def sync_cloud_account_domains(cloud_account):
    """
    同步云账号下的域名和DNS记录
    
    Args:
        cloud_account: CloudAccount实例
        
    Returns:
        dict: 同步结果统计
    """
    from .models import Domain, DNSRecord  # 避免循环导入
    
    try:
        # 获取DNS提供商实例
        provider = get_dns_provider(
            cloud_account.provider,
            cloud_account.access_key,
            cloud_account.get_decrypted_secret_key(),
            cloud_account.region
        )
        
        # 获取云端域名列表
        cloud_domains = provider.list_domains()
        
        sync_stats = {
            'domains_added': 0,
            'domains_updated': 0,
            'records_added': 0,
            'records_updated': 0,
            'errors': []
        }
        
        for domain_info in cloud_domains:
            try:
                # 创建或更新域名记录
                domain, created = Domain.objects.get_or_create(
                    name=domain_info['name'],
                    user=cloud_account.user,
                    defaults={
                        'cloud_account': cloud_account,
                        'zone_id': domain_info.get('zone_id', ''),
                        'is_active': True
                    }
                )
                
                if created:
                    sync_stats['domains_added'] += 1
                    logger.info(f"添加新域名: {domain.name}")
                else:
                    # 更新现有域名信息
                    domain.zone_id = domain_info.get('zone_id', domain.zone_id)
                    domain.last_sync = timezone.now()
                    domain.save()
                    sync_stats['domains_updated'] += 1
                    logger.info(f"更新域名: {domain.name}")
                
                # 同步该域名下的DNS记录
                try:
                    cloud_records = provider.list_records(domain.name, domain.zone_id)
                    
                    for record_info in cloud_records:
                        try:
                            # 创建或更新DNS记录
                            record, created = DNSRecord.objects.get_or_create(
                                domain=domain,
                                name=record_info['name'],
                                record_type=record_info['type'],
                                value=record_info['value'],
                                user=cloud_account.user,
                                defaults={
                                    'ttl': record_info.get('ttl', 600),
                                    'priority': record_info.get('priority', 0),
                                    'record_id': record_info.get('record_id', ''),
                                    'is_active': True
                                }
                            )
                            
                            if created:
                                sync_stats['records_added'] += 1
                                logger.info(f"添加DNS记录: {record.name}.{domain.name} ({record.record_type})")
                            else:
                                # 更新现有记录信息
                                record.ttl = record_info.get('ttl', record.ttl)
                                record.priority = record_info.get('priority', record.priority)
                                record.record_id = record_info.get('record_id', record.record_id)
                                record.save()
                                sync_stats['records_updated'] += 1
                                logger.info(f"更新DNS记录: {record.name}.{domain.name} ({record.record_type})")
                                
                        except Exception as e:
                            error_msg = f"同步DNS记录失败 {record_info.get('name', '')}.{domain.name}: {e}"
                            sync_stats['errors'].append(error_msg)
                            logger.error(error_msg)
                            
                except Exception as e:
                    error_msg = f"获取域名 {domain.name} 的DNS记录失败: {e}"
                    sync_stats['errors'].append(error_msg)
                    logger.error(error_msg)
                    
            except Exception as e:
                error_msg = f"处理域名 {domain_info.get('name', '')} 失败: {e}"
                sync_stats['errors'].append(error_msg)
                logger.error(error_msg)
        
        # 更新云账号的最后同步时间
        cloud_account.updated_at = timezone.now()
        cloud_account.save()
        
        return sync_stats
        
    except Exception as e:
        error_msg = f"同步云账号 {cloud_account.name} 失败: {e}"
        logger.error(error_msg)
        return {
            'domains_added': 0,
            'domains_updated': 0,
            'records_added': 0,
            'records_updated': 0,
            'errors': [error_msg]
        }